/**
 * Default namespace
 */
var jqtools = {
    exceptionType: "jqtools.exception",
    
    /**
     * Creates an exception.
     * @param {Object} message
     */
    exceptionFactory: {
        create: function(message){
            return {
                type: jqtools.exceptionType,
                "message": message
            };
        }
    }
};

/**
 * String template
 * @param {String} string
 */
function StringTemplate(string){

    /**
     * Process template.
     * @param {JSON} data
     * @return {String} Returns the processed string.
     */
    StringTemplate.prototype.process = function(data){
        var result = string;
        for (var key in data) {
            var templateKey = "${" + key + "}";
            result = result.replace(templateKey, data[key]);
        }
        return result;
    };
}

jQuery.fn.tools = function(context){



    /**
     * Throws special exception.
     * @param {String} message
     */
    var e = function(message){
        throw jqtools.exceptionFactory.create(message);
    };
    
    var self = this;
    
    /**
     * contains default checks for context.
     */
    var defaultChecks = function(){
        if (!$.isArray(context)) {
            e("context should be an array");
        }
        if (context.length <= 0) {
            e("context should not be empty");
        }
        for (var index in context) {
            var element = context[index];
            if (!$.isPlainObject(element)) {
                e("context should only contains plain objects");
            }
            if (element.id == null) {
                e("each element in context should have an id");
            }
        }
        
    };
    
    defaultChecks();
    
    /**
     * Checks selector.
     */
    var checkSelector = function(){
        if (self.length == 0) {
            e("selector " + self.selector + " selects nothing");
        }
    };
    
    
    
    var toolTemplate = new StringTemplate("<img id='${id}' class='tool' src='${icon}'>");
    var defaultToolDescription = {
        instance: function(){
            var result = {};
            for (var property in this) {
                result[property] = this[property];
            }
            return result;
        }
    };
    var defaultConfig = {
        size: 64,
        max: 100
    }
    
    /**
     * Creates string representation of a tool.
     * @param {JSON} description
     * @return {String}
     */
    var createToolFrom = function(description){
        var toolDescription = $.extend(defaultToolDescription.instance(), description);
        return toolTemplate.process(toolDescription);
    };
    
    /**
     * Appends tool strings to selected toolbar.
     * @param {Array} tools
     */
    var appendTools = function(tools){
        var toolsString = "";
        for (var toolIndex in tools) {
            toolsString += tools[toolIndex];
        }
        self.append(toolsString);
    };
    
    var appendMocks = function(tools){
        var mockTool = createToolFrom({});
        tools = $(mockTool + mockTool).add(tools);
        tools = tools.add(mockTool + mockTool);
        return tools;
    }
    
    /**
     * Removes all tools from current toolbar.
     */
    var clearToolbar = function(){
        var tools = self.find(".tool");
        if (tools.length > 0) {
            tools.remove();
        }
    };
    
    /**
     * Calculates size of concerned tools and stores them.
     */
    var recalculateSize = function(event){
        var tools = self.find(".tool");
        var focusedToolIndex = tools.index(event.target);
        var clone = tools.clone();
        var extendedTools = appendMocks(clone);
        var concernedTools = extendedTools.filter(function(index, element){
            return Math.abs(focusedToolIndex - index) <= 2;
        });
        
        console.log(concernedTools);
    };
    
    /**
     * Should be used to resize tools.
     * @param {Function} strategy Strategy is used to resize tools. e.g. AnimatedRenderStrategy, DefaultRenderStrategy
     */
    var render = function(strategy){
        //TODO: read data
        strategy();
    };
    
    /**
     * Initializes current toolbar.
     */
    var init = function(){
        var tools = self.find(".tool");
        tools.css("width", defaultConfig.size);
        tools.css("float", "left");
        tools.css("height", defaultConfig.size);
        
        var toolbarWidth = 0;
        tools.each(function(index, element){
            toolbarWidth += element.width;
        });
        self.css("width", toolbarWidth);
        tools.mousemove(function(event){
            recalculateSize(event);
            render(function(){
            });
        });
    };
    
    /**
     * Clears current toolbar and appends all tools from context.
     */
    this.use = function(){
        checkSelector();
        clearToolbar();
        
        var tools = [];
        for (var toolIndex in context) {
            var tool = createToolFrom(context[toolIndex]);
            tools.push(tool);
        }
        
        appendTools(tools);
        init();
        return this;
    };
    
    
    return this;
};



